﻿
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<!-- saved from url=(0014)about:internet -->
<html xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:mssdk="winsdk" xmlns:script="urn:script" xmlns:build="urn:build" xmlns:MSHelp="http://msdn.microsoft.com/mshelp">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="Description" content="This topic provides the following user and kernel mode JavaScript code samples.Data Filtering: Plug and Play Device Tree in KD (Kernel Mode)Extend Devices Specific To Multimedia (Kernel Mode)Adding Bus Information to _DEVICE_OBJECT (Kernel Mode)Find an Application Title (User Mode)."/>
<meta name="MSHAttr" content="PreferredSiteName:MSDN"/>
<meta name="MSHAttr" content="PreferredLib:/library/windows/hardware"/>
<title>JavaScript Debugger Example Scripts</title>



<link rel="STYLESHEET" type="text/css" HREF="../common/backsdk4.css"/>





<style>
html,div { margin: 0; padding: 0;}

body {
	padding: 0px;
	margin: 0px;
	overflow: auto;
	height: 100%;
}

#winchm_template_button{
	float: right;
	width: 93px;
	top: 7px;
	position: relative;
	text-align: right;
	right: 5px;
	height: auto;
}

#winchm_template_top{
	padding: 0px;
	margin: 0px;
	border-bottom: 1px solid #9B9B9B;
	background-color: #B1CEFE;
}

#winchm_template_navigation{
	margin: 0px;
	padding-top: 7px;
	padding-left: 7px;
	padding-bottom: 3px;
	padding-right: 0px;
	font-size: 8.5pt;
	font-family: Arial, Helvetica, sans-serif;
	font-weight: normal;
	color: #585858;
}

#winchm_template_title{
	margin: 0px;
	padding-top: 4px;
	padding-left: 7px;
	padding-bottom: 7px;
	padding-right: 0px;
	font-size: 18px; 
	font-family: Verdana, Geneva, sans-serif;
	color: #363636;
}

#winchm_template_content{
	margin-top: 20px;
	margin-left: 15px;
	margin-bottom: 20px;
	margin-right: 15px;
	width: auto  !important;
	width: 100%;
}

#winchm_template_footer{
	border-width: 1px;
	border-color: #B1CEFE;
	border-top-style: solid;
	margin-top: 15px;
	margin-left: 15px;
	margin-bottom: 20px;
	margin-right: 15px;
	padding-top: 7px;
	padding-left: 0px;
	padding-bottom: 0px;
	padding-right: 0px;
	font-family: arial, helvetica, sans-serif;
	font-size: 8.5pt;
	color: #696969;
	width: auto;
	text-align: left;
}


#winchm_template_container{
	margin: 0px;
	padding: 0px;
	position: static;
	padding-bottom: 3px;
	overflow: auto;
	background-color: #FFFFFF;
}


@media print
{
#winchm_template_container{
	position: static;	
	margin: 0px;
	padding: 5px;
	
	width: auto;
	height: auto;
	overflow: auto;
}
#winchm_template_button{
visibility:hidden;
}
}

#winchm_template_navigation A:link	{text-decoration: none; color:#004080}
#winchm_template_navigation A:visited  {text-decoration: none; color: #004080}
#winchm_template_navigation A:active {text-decoration: none; color: #004080 }
#winchm_template_navigation A:hover {text-decoration: none;color: #0080FF}

A:link	{text-decoration: underline; color:#0033CC}
A:visited  {text-decoration: underline; color: #0033CC}
A:active {text-decoration: underline; color: #0033CC }
A:hover {text-decoration: underline;color: #FF0000;}
</style>
<script type="text/javascript">
function isMobile(){
Agent = window.navigator.userAgent;
if (Agent.indexOf("iPhone")>=1 || Agent.indexOf("iPad")>=1 || Agent.indexOf("iPod")>=1 || Agent.indexOf("Android")>=1){
return true;
}else{
return false;	
}

}
function d_onresize(){
if (window.navigator.userAgent.indexOf("MSIE")>=1){
document.getElementById('winchm_template_container').style.pixelWidth = document.body.offsetWidth - 3;
document.getElementById('winchm_template_container').style.pixelHeight = document.body.offsetHeight - document.getElementById('winchm_template_top').offsetHeight - 4;
}
document.getElementById('winchm_template_container').style.top = document.getElementById('winchm_template_top').offsetHeight + 'px';
}

function d_onbeforeprint(){
document.getElementById('winchm_template_container').style.width = 'auto';
document.getElementById('winchm_template_container').style.height = 'auto';
}

function d_onafterprint(){
d_onresize();
}

if(!isMobile()){

window.onload = d_onresize;
window.onresize = d_onresize;
window.onbeforeprint = d_onbeforeprint;
window.onafterprint = d_onafterprint;

document.write("<style>\n");
document.write("body {overflow: hidden;}\n");
document.write("#winchm_template_container {position: absolute;overflow: auto;top : 0px;right: 0px;bottom: 0px;left: 0px;}\n");
document.write("</style>\n");
}

</script>
</head>
<body><script language="JavaScript" type="text/JavaScript">
function syn(){
if(parent.nav.tree){
 if(parent.nav.tree.loaded){
  parent.nav.tree.selectNode(1176);
 }else{
  setTimeout("syn()",500);
}
  }else{
  setTimeout("syn()",500);
  }}
if(parent!=self){
  setTimeout("syn()",100);
}else{
  parent.location.href = "../../index.htm?page=debugger/javascript_debugger_example_scripts.htm";
}
originalOnload = window.onload;
if(originalOnload==null){
window.onload = function(){parent.contentLoaded = true;};
}else{
window.onload = function(){originalOnload();parent.contentLoaded = true;};
}
</script> 


<div id="winchm_template_top">
	<div id="winchm_template_button"><A href="javascript_debugger_scripting.htm" title="Previous topic"><img id="winchm_template_prev" alt="Previous topic" src="../template2/btn_prev_n.gif" border="0"></a><A href="native_objects_in_javascript_extensions.htm" title="Next topic"><img id="winchm_template_next" alt="Next topic" src="../template2/btn_next_n.gif" border="0"></a></div>
	<div id="winchm_template_navigation">Help &gt; 
<A href="introduction6.htm">Debugging Tools for Windows (WinDbg, KD, CDB, NTSD)</A> &gt; <A href="debugging_resources.htm">Debugging Resources</A> &gt; <A href="javascript_debugger_scripting.htm">JavaScript Debugger Scripting</A> &gt; </div>
	<div id="winchm_template_title">JavaScript Debugger Example Scripts</div>
</div>
<div id="winchm_template_container">
	<div id="winchm_template_content"><div id="mainSection"><p>This topic provides the following  user and kernel mode JavaScript code samples.<ul>
<li><a href="#Bookmark1176">Data Filtering: Plug and Play Device Tree in KD (Kernel Mode)</a></li>
<li><a href="#Bookmark1176">Extend Devices Specific To Multimedia (Kernel Mode)</a></li>
<li><a href="#Bookmark1176">Adding Bus Information to _DEVICE_OBJECT (Kernel Mode)</a></li>
<li><a href="#Bookmark1176">Find an Application Title (User Mode)</a></li>
</ul>
</p>
<h2><a id="Working_with_Samples"></a><a id="working_with_samples"></a><a id="WORKING_WITH_SAMPLES"></a>Working with Samples</h2>
<p>Use the general process to test any of the samples.</p>
<dl>
<dd>
<p>1. Determine if the sample JavaScript is intended for kernel or user mode debugging. Then either load an appropriate  dump file or establish a live connection to a target system.</p>
</dd>
<dd>
<p>2. Use a text editor such as Notepad to create a text file named and save it with a .js file extension, such as <i>HelloWorld.js </i></p>
<div class="code"><span codelanguage=""><table>
<tr>
<th></th>
</tr>
<tr>
<td>
<pre>// WinDbg JavaScript sample
// Says Hello World!

// Code at root will be run with .scriptrun and .scriptload
host.diagnostics.debugLog("***&gt; Hello World! \n");

function sayHi()
{
   //Say Hi 
   host.diagnostics.debugLog("Hi from JavaScript! \n");
}</pre>
</td>
</tr>
</table></span></div>
</dd>
<dd>
<p>3. Use the <a href="#Bookmark2133"><b>.load (Load Extension DLL)</b></a> command to load the JavaScript provider. </p>
<div class="code"><span codelanguage=""><table>
<tr>
<th></th>
</tr>
<tr>
<td>
<pre>0:000&gt; .load jsprovider.dll</pre>
</td>
</tr>
</table></span></div>
</dd>
<dd>
<p>4. Use the <a href="#Bookmark2173"><b>.scriptrun (Run Script)</b></a>command to load and execute the script. The .scriptrun command will run code at the root/top and the code under the function names  <i>initializeScript</i> and <i>invokeScript</i>. </p>
<div class="code"><span codelanguage=""><table>
<tr>
<th></th>
</tr>
<tr>
<td>
<pre>0:000&gt; .scriptrun c:\WinDbg\Scripts\HelloWorld.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\HelloWorld.js'
***&gt; Hello World! 
</pre>
</td>
</tr>
</table></span></div>
</dd>
<dd>
<p>5. If the script contains a uniquely named function, use the dx command to execute that function, that is located in Debugger.State.Scripts.<i>ScriptName</i>.Contents.<i>FunctionName</i>.</p>
<div class="code"><span codelanguage=""><table>
<tr>
<th></th>
</tr>
<tr>
<td>
<pre>0:001&gt; dx Debugger.State.Scripts.HelloWorld.Contents.sayHi()
Hi from JavaScript!
Debugger.State.Scripts.HelloWorld.Contents.sayHi()</pre>
</td>
</tr>
</table></span></div>
</dd>
</dl>
<p>Refer to <a href="#Bookmark1175">JavaScript Debugger Scripting</a> for additional information about working with JavaScript.</p>
<h2><a id="Filter"></a><a id="filter"></a><a id="FILTER"></a>Data Filtering: Plug and Play Device Tree in KD (Kernel Mode)</h2>
<p>This sample code filters the device node tree to display just devices that contain a path of PCI that are started. </p>
<p>This script  is intended to support kernel mode debugging.</p>
<p>You can use the !devnode 0 1 command  to display information about the device tree. For more information, see <a href="#Bookmark2321"><b>!devnode</b></a>.</p>
<div class="code"><span codelanguage=""><table>
<tr>
<th></th>
</tr>
<tr>
<td>
<pre>// PlugAndPlayDeviceTree.js
// An ES6 generator function which recursively filters the device tree looking for PCI devices in the started state.
//
function *filterDevices(deviceNode)
{
    //
    // If the device instance path has "PCI" in it and is started (state == 776), yield it from the generator.
    //
    if (deviceNode.InstancePath.indexOf("PCI") != -1 &amp;&amp; deviceNode.State == 776)
    {
        yield deviceNode;
    }
 
    //
    // Recursively invoke the generator for all children of the device node.
    //
    for (var childNode of deviceNode.Children)
    {
        yield* filterDevices(childNode);
    }
}
 
//
// A function which finds the device tree of the first session in the debugger and passes it to our filter function.
//
function filterAllDevices()
{
    return filterDevices(host.namespace.Debugger.Sessions.First().Devices.DeviceTree.First());
}</pre>
</td>
</tr>
</table></span></div>
<p>Either load a kernel dump file or establish a kernel mode connection to a target system.</p>
<div class="code"><span codelanguage=""><table>
<tr>
<th></th>
</tr>
<tr>
<td>
<pre>0: kd&gt; !load jsprovider.dll</pre>
</td>
</tr>
</table></span></div>
<div class="code"><span codelanguage=""><table>
<tr>
<th></th>
</tr>
<tr>
<td>
<pre>0: kd&gt; .scriptload c:\WinDbg\Scripts\deviceFilter.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\deviceFilter.js'
</pre>
</td>
</tr>
</table></span></div>
<p>Call the filterAllDevices() function.</p>
<div class="code"><span codelanguage=""><table>
<tr>
<th></th>
</tr>
<tr>
<td>
<pre>0: kd&gt; dx Debugger.State.Scripts.PlugAndPlayDeviceTree.Contents.filterAllDevices()
Debugger.State.Scripts.PlugAndPlayDeviceTree.Contents.filterAllDevices()                 : [object Generator]
    [0x0]            : PCI\VEN_8086&amp;DEV_D131&amp;SUBSYS_304A103C&amp;REV_11\3&amp;21436425&amp;0&amp;00
    [0x1]            : PCI\VEN_8086&amp;DEV_D138&amp;SUBSYS_304A103C&amp;REV_11\3&amp;21436425&amp;0&amp;18 (pci)
    [0x2]            : PCI\VEN_10DE&amp;DEV_06FD&amp;SUBSYS_062E10DE&amp;REV_A1\4&amp;324c21a&amp;0&amp;0018 (nvlddmkm)
    [0x3]            : PCI\VEN_8086&amp;DEV_3B64&amp;SUBSYS_304A103C&amp;REV_06\3&amp;21436425&amp;0&amp;B0 (HECIx64)
    [0x4]            : PCI\VEN_8086&amp;DEV_3B3C&amp;SUBSYS_304A103C&amp;REV_05\3&amp;21436425&amp;0&amp;D0 (usbehci)
    [0x5]            : PCI\VEN_8086&amp;DEV_3B56&amp;SUBSYS_304A103C&amp;REV_05\3&amp;21436425&amp;0&amp;D8 (HDAudBus)
...</pre>
</td>
</tr>
</table></span></div>
<p>Each of these objects presented above, automatically supports DML, and can be clicked through just as with any other dx query. 
</p>
<p>Alternatively to using this script, it is possible to use a LINQ query to accomplish a similar result.</p>
<p></p>
<div class="code"><span codelanguage=""><table>
<tr>
<th></th>
</tr>
<tr>
<td>
<pre>0: kd&gt; dx @$cursession.Devices.DeviceTree.Flatten(n =&gt; n.Children).Where(n =&gt; n.InstancePath.Contains("PCI") &amp;&amp; n.State == 776)
@$cursession.Devices.DeviceTree.Flatten(n =&gt; n.Children).Where(n =&gt; n.InstancePath.Contains("PCI") &amp;&amp; n.State == 776)  
    [0x0]            : PCI\VEN_8086&amp;DEV_D131&amp;SUBSYS_304A103C&amp;REV_11\3&amp;21436425&amp;0&amp;00
    [0x1]            : PCI\VEN_8086&amp;DEV_D138&amp;SUBSYS_304A103C&amp;REV_11\3&amp;21436425&amp;0&amp;18 (pci)
    [0x2]            : PCI\VEN_10DE&amp;DEV_06FD&amp;SUBSYS_062E10DE&amp;REV_A1\4&amp;324c21a&amp;0&amp;0018 (nvlddmkm)
    [0x3]            : PCI\VEN_8086&amp;DEV_3B64&amp;SUBSYS_304A103C&amp;REV_06\3&amp;21436425&amp;0&amp;B0 (HECIx64)
    [0x4]            : PCI\VEN_8086&amp;DEV_3B3C&amp;SUBSYS_304A103C&amp;REV_05\3&amp;21436425&amp;0&amp;D0 (usbehci)
    [0x5]            : PCI\VEN_8086&amp;DEV_3B56&amp;SUBSYS_304A103C&amp;REV_05\3&amp;21436425&amp;0&amp;D8 (HDAudBus)
...</pre>
</td>
</tr>
</table></span></div>
<h2><a id="Multimedia"></a><a id="multimedia"></a><a id="MULTIMEDIA"></a>Extend Devices Specific To Multimedia (Kernel Mode)</h2>
<p>This larger JavaScript example  extends a kernel _DEVICE_OBJECT for information specific to multimedia and adds StreamingDevices to a debugger session. </p>
<p>This script  is intended to support kernel mode debugging.</p>
<p>Note that the choice to extend Session with StreamingDevices is done for example purposes only. This should be either left to _DEVICE_OBJECT only or deeper inside a namespace under the existing .Devices.* hierarchy. </p>
<div class="code"><span codelanguage=""><table>
<tr>
<th></th>
</tr>
<tr>
<td>
<pre>// StreamingFinder.js
// Extends a kernel _DEVICE_OBJECT for information specific to multimedia 
// and adds StreamingDevices to a debugger session.
//

"use strict";
 
function initializeScript()
{
    // isStreamingDeviceObject: 
    //
    // Returns whether devObj (as a _DEVICE_OBJECT -- not a pointer) looks like it is a device
    // object for a streaming device.
    //
    function isStreamingDeviceObject(devObj)
    {
        try
        {
            var devExt = devObj.DeviceExtension;
            var possibleStreamingExtPtrPtr = host.createPointerObject(devExt.address, "ks.sys", "_KSIDEVICE_HEADER **", devObj);
            var possibleStreamingExt = possibleStreamingExtPtrPtr.dereference().dereference();
            var baseDevice = possibleStreamingExt.BaseDevice;
 
            if (devObj.targetLocation == baseDevice.dereference().targetLocation)
            {
                return true;
            }
        }
        //
        // The above code expects to fail (walking into invalid or paged out memory) often.  A failure to read the memory
        // of the target process will result in an exception.  Catch such exception and indicate that the object does not
        // match the profile of a "streaming device object".
        //
        catch(exc)
        {   
        }
 
        return false;
    }
 
    // findStreamingFDO(pdo):
    //
    // From a physical device object, walks up the device stack and attempts to find a device which
    // looks like a streaming device (and is thus assumed to be the FDO).  pdo is a pointer to 
    // the _DEVICE_OBJECT for the pdo.
    //
    function findStreamingFDO(pdo)
    {
        for (var device of pdo.UpperDevices)
        {
            if (isStreamingDeviceObject(device.dereference()))
            {
                return device;
            }
        }
 
        return null;
    }
 
    // streamingDeviceList:
    //
    // A class which enumerates all streaming devices on the system.
    //
    class streamingDeviceList
    {
        constructor(session)
        {
            this.__session = session;
        }
 
        *[Symbol.iterator]()
        {
            //
            // Get the list of all PDOs from PNP using LINQ:
            //
            var allPDOs = this.__session.Devices.DeviceTree.Flatten(function(dev) { return dev.Children; })
                                                           .Select (function(dev) { return dev.PhysicalDeviceObject; });
 
            //
            // Walk the stack up each PDO to find the functional device which looks like a KS device.  This is
            // a very simple heuristic test: the back pointer to the device in the KS device extension is
            // accurate.  Make sure this is wrapped in a try/catch to avoid invalid memory reads causing
            // us to bail out.
            //
            // Don't even bother checking the PDO.
            //
            for (var pdo of allPDOs)
            {
                var fdo = findStreamingFDO(pdo);
                if (fdo != null)
                {
                    yield fdo;
                }
            }
        }
   }
 
    // streamingDeviceExtension:
    //
    // An object which will extend "session" and include the list of streaming devices.
    //
    class streamingDeviceExtension
    {
        get StreamingDevices()
        {
            return new streamingDeviceList(this);
        }
    };
 
    // createEntryList:
    //
    // An abstraction over the create entry list within a streaming device.
    //    
    class createEntryList
    {
        constructor(ksHeader)
        {
            this.__ksHeader = ksHeader;
        }
 
        *[Symbol.iterator]()
        {
            for (var entry of host.namespace.Debugger.Utility.Collections.FromListEntry(this.__ksHeader.ChildCreateHandlerList, "ks!KSICREATE_ENTRY", "ListEntry"))
            {
 															if (!entry.CreateItem.Create.isNull)
                {
                    yield entry;
                }
            }
        }
    }
 
    // streamingInformation:
    //
    // Represents the streaming state of a device.
    //    
    class streamingInformation
    {
        constructor(fdo)
        {
            this.__fdo = fdo;
 
            var devExt = fdo.DeviceExtension;
            var streamingExtPtrPtr = host.createPointerObject(devExt.address, "ks.sys", "_KSIDEVICE_HEADER **", fdo);
            this.__ksHeader = streamingExtPtrPtr.dereference().dereference();
        }
 
        get CreateEntries()
        {
            return new createEntryList(this.__ksHeader);
        }
    }
 
    // createEntryVisualizer:
    //
    // A visualizer for KSICREATE_ENTRY
    //
    class createEntryVisualizer
    {
        toString()
        {
            return this.CreateItem.ObjectClass.toString();
        }
 
        get CreateContext()
        {
            //
            // This is probably not entirely accurate.  The context is not *REQUIRED* to be an IUnknown.
            // More analysis should probably be performed.
            //
            return host.createTypedObject(this.CreateItem.Context.address, "ks.sys", "IUnknown", this);
        }
    }
 
    // deviceExtension:
    //
    // Extends our notion of a device in the device tree to place streaming information on
    // top of it.
    //
    class deviceExtension
    {
        get StreamingState()
        {
            if (isStreamingDeviceObject(this))
            {
                return new streamingInformation(this);
            }
 
            //
            // If we cannot find a streaming FDO, returning undefined will indicate that there is no value
            // to the property.
            //
            return undefined;
        }
    }
 
    return [new host.namedModelParent(streamingDeviceExtension, "Debugger.Models.Session"),
            new host.typeSignatureExtension(deviceExtension, "_DEVICE_OBJECT"),
            new host.typeSignatureRegistration(createEntryVisualizer, "KSICREATE_ENTRY")]
}</pre>
</td>
</tr>
</table></span></div>
<p>First load the script provider as described previously. Then load the script.</p>
<div class="code"><span codelanguage=""><table>
<tr>
<th></th>
</tr>
<tr>
<td>
<pre>0: kd&gt; .scriptload c:\WinDbg\Scripts\StreamingFinder.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\StreamingFinder.js'
</pre>
</td>
</tr>
</table></span></div>
<p>Then use the dx command to access the new StreamingDevices capabilities that the script provides. </p>
<div class="code"><span codelanguage=""><table>
<tr>
<th></th>
</tr>
<tr>
<td>
<pre>0: kd&gt; dx -r3 @$cursession.StreamingDevices.Select(d =&gt; d-&gt;StreamingState.CreateEntries)
@$cursession.StreamingDevices.Select(d =&gt; d-&gt;StreamingState.CreateEntries)                
    [0x0]            : [object Object]
        [0x0]            : "e0HDMIOutTopo" [Type: KSICREATE_ENTRY]
            [&lt;Raw View&gt;]     [Type: KSICREATE_ENTRY]
            CreateContext    [Type: CPortTopology]
    [0x1]            : [object Object]
        [0x0]            : "AnalogDigitalCaptureTopo" [Type: KSICREATE_ENTRY]
            [&lt;Raw View&gt;]     [Type: KSICREATE_ENTRY]
            CreateContext    [Type: CPortTopology]
        [0x1]            : "AnalogDigitalCapture1Topo" [Type: KSICREATE_ENTRY]
            [&lt;Raw View&gt;]     [Type: KSICREATE_ENTRY]
            CreateContext    [Type: CPortTopology]
        [0x2]            : "AnalogDigitalCapture2Topo" [Type: KSICREATE_ENTRY]
            [&lt;Raw View&gt;]     [Type: KSICREATE_ENTRY]
            CreateContext    [Type: CPortTopology]
        [0x3]            : "AnalogDigitalCapture2Wave" [Type: KSICREATE_ENTRY]
            [&lt;Raw View&gt;]     [Type: KSICREATE_ENTRY]
            CreateContext    [Type: CPortWaveRT]
        [0x4]            : "HeadphoneTopo" [Type: KSICREATE_ENTRY]
            [&lt;Raw View&gt;]     [Type: KSICREATE_ENTRY]
            CreateContext    [Type: CPortTopology]
        [0x5]            : "RearLineOutTopo" [Type: KSICREATE_ENTRY]
            [&lt;Raw View&gt;]     [Type: KSICREATE_ENTRY]
            CreateContext    [Type: CPortTopology]
        [0x6]            : "RearLineOutWave" [Type: KSICREATE_ENTRY]
            [&lt;Raw View&gt;]     [Type: KSICREATE_ENTRY]
            CreateContext    [Type: CPortWaveRT]
    [0x2]            : [object Object]
        [0x0]            : "GLOBAL" [Type: KSICREATE_ENTRY]
            [&lt;Raw View&gt;]     [Type: KSICREATE_ENTRY]
            CreateContext    [Type: IUnknown]</pre>
</td>
</tr>
</table></span></div>
<h2><a id="Bus"></a><a id="bus"></a><a id="BUS"></a>Adding Bus Information to _DEVICE_OBJECT (Kernel Mode)</h2>
<p></p>
<p>This script extends the visualization of _DEVICE_OBJECT to add a BusInformation field which has PCI specific information underneath it. The manner and namespacing of this sample are still being discussed. It should be considered a sample of the capabilities of the JavaScript provider. </p>
<p>This script  is intended to support kernel mode debugging.</p>
<div class="code"><span codelanguage=""><table>
<tr>
<th></th>
</tr>
<tr>
<td>
<pre>"use strict";

/*************************************************
DeviceExtensionInformation.js:

An example which extends _DEVICE_OBJECT to add bus specific information
to each device object.

NOTE: The means of conditionally adding and the style of namespacing this
are still being discussed.  This currently serves as an example of the capability
of JavaScript extensions.

*************************************************/

function initializeScript()
{
    // __getStackPDO():
    //
    // Returns the physical device object of the device stack whose device object
    // is passed in as 'devObj'.
    //
    function __getStackPDO(devObj)
    {
        var curDevice = devObj;
        var nextDevice = curDevice.DeviceObjectExtension.AttachedTo;
        while (!nextDevice.isNull)
        {
            curDevice = nextDevice;
            nextDevice = curDevice.DeviceObjectExtension.AttachedTo;
        }
        return curDevice;
    }
    
    // pciInformation:
    //
    // Class which abstracts our particular representation of PCI information for a PCI device or bus
    // based on a _PCI_DEVICE structure or a _PCI_BUS structure.
    //
    class pciInformation
    {
        constructor(pciDev)
        {
            this.__pciDev = pciDev;
            this.__pciPDO = __getStackPDO(this.__pciDev);
            this.__isBridge = (this.__pciDev.address != this.__pciPDO.address);
            
            if (this.__isBridge)
            {
                this.__deviceExtension = host.createTypedObject(this.__pciPDO.DeviceExtension.address, "pci.sys", "_PCI_DEVICE", this.__pciPDO);
                this.__busExtension = host.createTypedObject(this.__pciDev.DeviceExtension.address, "pci.sys", "_PCI_BUS", this.__pciPDO);
                
                this.__hasDevice = (this.__deviceExtension.Signature == 0x44696350); /* 'PciD' */
                this.__hasBus = (this.__busExtension.Signature == 0x42696350); /* 'PciB' */
                
                if (!this.__hasDevice &amp;&amp; !this.__hasBus)
                {
                    throw new Error("Unrecognized PCI device extension");
                }
            }
            else
            {
                this.__deviceExtension = host.createTypedObject(this.__pciPDO.DeviceExtension.address, "pci.sys", "_PCI_DEVICE", this.__pciPDO);
                
                this.__hasDevice = (this.__deviceExtension.Signature == 0x44696350); /* 'PciD' */
                this.__hasBus = false;
                
                if (!this.__hasDevice)
                {
                    throw new Error("Unrecognized PCI device extension");
                }
            }
        }
        
        toString()
        {
            
            if (this.__hasBus &amp;&amp; this.__hasDevice)
            {
                return "Bus: " + this.__busExtension.toString() + " Device: " + this.__deviceExtension.toString();
            }
            else if (this.__hasBus)
            {
                return this.__busExtension.toString();
            }
            else
            {
                return this.__deviceExtension.toString();
            }
        }
        
        get Device()
        {
            if (this.__hasDevice)
            {
                // NatVis supplies the visualization for _PCI_DEVICE
                return this.__deviceExtension;
            }
            
            return undefined;
        }
        
        get Bus()
        {
            if (this.__hasBus)
            {
                // NatVis supplies the visualization for _PCI_BUS
                return this.__busExtension;
            }
            
            return undefined;
        }
    }
    
    // busInformation:
    //
    // Our class which does analysis of what bus a particular device is on and places information about
    // about that bus within the _DEVICE_OBJECT visualization.
    //
    class busInformation
    {
        constructor(devObj)
        {
            this.__devObj = devObj;
        }
        
        get PCI()
        {
            //
            // Check the current device object.  This may be a PCI bridge
            // in which both the FDO and PDO are relevant (one for the bus information
            // and one for the bridge device information).
            //
            var curName = this.__devObj.DriverObject.DriverName.toString();
            if (curName.includes("\\Driver\\pci"))
            {
                return new pciInformation(this.__devObj);
            }
            
            var stackPDO = __getStackPDO(this.__devObj);
            var pdoName = stackPDO.DriverObject.DriverName.toString();
            if (pdoName.includes("\\Driver\\pci"))
            {
                return new pciInformation(stackPDO);
            }
            
            return undefined;
        }
    }
    
    // busInformationExtension:
    //
    // An extension placed on top of _DEVICE_OBJECT in order to provide bus analysis and bus specific
    // information to the device.
    //
    class busInformationExtension
    {
        get BusInformation()
        {
            return new busInformation(this);
        }
    }
    
    return [new host.typeSignatureExtension(busInformationExtension, "_DEVICE_OBJECT")];
}
</pre>
</td>
</tr>
</table></span></div>
<p>First load the script provider as described previously. Then load the script.</p>
<div class="code"><span codelanguage=""><table>
<tr>
<th></th>
</tr>
<tr>
<td>
<pre>0: kd&gt; .scriptload c:\WinDbg\Scripts\DeviceExtensionInformation.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\DeviceExtensionInformation.js'
</pre>
</td>
</tr>
</table></span></div>
<p>We need to locate the address of the device object we are interested in. In this example, we will examine the audio HDAudBus driver.</p>
<div class="code"><span codelanguage=""><table>
<tr>
<th></th>
</tr>
<tr>
<td>
<pre>0: kd&gt;  !drvobj HDAudBus
Driver object (ffffb60757a4ae60) is for:
 \Driver\HDAudBus
Driver Extension List: (id , addr)
(fffff8050a9eb290 ffffb60758413180)  
Device Object list:
ffffb60758e21810  ffffb60757a67c60</pre>
</td>
</tr>
</table></span></div>
<p>After the script is loaded use the dx command to display bus information for device objects.</p>
<div class="code"><span codelanguage=""><table>
<tr>
<th></th>
</tr>
<tr>
<td>
<pre>0: kd&gt; dx -r1 (*((ntkrnlmp!_DEVICE_OBJECT *)0xffffe00001b567c0))
(*((ntkrnlmp!_DEVICE_OBJECT *)0xffffe00001b567c0))                 : Device for "\Driver\HDAudBus" [Type: _DEVICE_OBJECT]
    [&lt;Raw View&gt;]     [Type: _DEVICE_OBJECT]
    Flags            : 0x2004
    UpperDevices     : None
    LowerDevices     : Immediately below is Device for "\Driver\ACPI" [at 0xffffe000003d9820]
    Driver           : 0xffffe00001ccd060 : Driver "\Driver\HDAudBus" [Type: _DRIVER_OBJECT *]
    BusInformation   : [object Object]

0: kd&gt; dx -r1 (*((ntkrnlmp!_DEVICE_OBJECT *)0xffffe00001b567c0)).@"BusInformation"
(*((ntkrnlmp!_DEVICE_OBJECT *)0xffffe00001b567c0)).@"BusInformation"                 : [object Object]
    PCI              :  (d=0x14 f=0x2) Vendor=0x1022 Device=0x780d Multimedia Device / Unknown Sub Class

0: kd&gt; dx -r1 (*((ntkrnlmp!_DEVICE_OBJECT *)0xffffe00001b567c0)).@"BusInformation".@"PCI"
(*((ntkrnlmp!_DEVICE_OBJECT *)0xffffe00001b567c0)).@"BusInformation".@"PCI"                 :  (d=0x14 f=0x2) Vendor=0x1022 Device=0x780d Multimedia Device / Unknown Sub Class
    Device           :  (d=0x14 f=0x2) Vendor=0x1022 Device=0x780d Multimedia Device / Unknown Sub Class [Type: _PCI_DEVICE]

0: kd&gt; dx -r1 (*((pci!_PCI_DEVICE *)0xffffe000003fe1b0))
(*((pci!_PCI_DEVICE *)0xffffe000003fe1b0))                 :  (d=0x14 f=0x2) Vendor=0x1022 Device=0x780d Multimedia Device / Unknown Sub Class [Type: _PCI_DEVICE]
    [&lt;Raw View&gt;]     [Type: _PCI_DEVICE]
    Device           : 0xffffe000003fe060 : Device for "\Driver\pci" [Type: _DEVICE_OBJECT *]
    Requirements    
    Resources       

0: kd&gt; dx -r1 (*((pci!_PCI_DEVICE *)0xffffe000003fe1b0)).@"Resources"
(*((pci!_PCI_DEVICE *)0xffffe000003fe1b0)).@"Resources"                
    BaseAddressRegisters
    Interrupt        : Line Based -- Interrupt Line = 0x10 [Type: _PCI_DEVICE_INTERRUPT_RESOURCE]

0: kd&gt; dx -r1 (*((pci!_PCI_DEVICE *)0xffffe000003fe1b0)).@"Resources".@"BaseAddressRegisters"
(*((pci!_PCI_DEVICE *)0xffffe000003fe1b0)).@"Resources".@"BaseAddressRegisters"                
    [0x0]            : Memory Resource: 0xf0340000 of length 0x4000 [Type: _CM_PARTIAL_RESOURCE_DESCRIPTOR]
</pre>
</td>
</tr>
</table></span></div>
<p></p>
<h2><a id="Title"></a><a id="title"></a><a id="TITLE"></a>Find an Application Title (User Mode)</h2>
<p>This example iterates through all the threads in the debugger's current process, finds a frame which includes <i>__mainCRTStartup</i> and then returns the string from the StartupInfo.lpTitle within the CRT's startup. This script shows  examples of iteration, string manipulation, and LINQ queries within JavaScript. </p>
<p>This script  is intended to support user mode debugging.</p>
<div class="code"><span codelanguage=""><table>
<tr>
<th></th>
</tr>
<tr>
<td>
<pre>// TitleFinder.js
// A function which uses just JavaScript concepts to find the title of an application
//
function findTitle()
{
    var curProcess = host.currentProcess;
    for (var thread of curProcess.Threads)
    {
        for (var frame of thread.Stack.Frames)
        {
            if (frame.toString().includes("__mainCRTStartup"))
            {
                var locals = frame.LocalVariables;
 
                //
                // locals.StartupInfo.lpTitle is just an unsigned short *.  We need to actually call an API to
                // read the UTF-16 string in the target address space.  This would be true even if this were
                // a char* or wchar_t*.
                //
                return host.memory.readWideString(locals.StartupInfo.lpTitle);
            }
        }
    }
}
 
//
// A function which uses both JavaScript and integrated LINQ concepts to do the same.
//
function findTitleWithLINQ()
{
    var isMainFrame = function(frame) { return frame.toString().includes("__mainCRTStartup"); };
    var isMainThread = function(thread) { return thread.Stack.Frames.Any(isMainFrame); };
 
    var curProcess = host.currentProcess;
    var mainThread = curProcess.Threads.Where(isMainThread).First();
    var mainFrame = mainThread.Stack.Frames.Where(isMainFrame).First();
 
    var locals = mainFrame.LocalVariables;
 
    //
    // locals.StartupInfo.lpTitle is just an unsigned short *.  We need to actually call an API to
    // read the UTF-16 string in the target address space.  This would be true even if this were
    // a char* or wchar_t*.
    //
    return host.memory.readWideString(locals.StartupInfo.lpTitle);
}</pre>
</td>
</tr>
</table></span></div>
<p></p>
<div class="code"><span codelanguage=""><table>
<tr>
<th></th>
</tr>
<tr>
<td>
<pre>0: kd&gt; .scriptload c:\WinDbg\Scripts\TitleFinder.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\TitleFinder.js'</pre>
</td>
</tr>
</table></span></div>
<p>Calling  the findTitle() function returns notepad.exe</p>
<div class="code"><span codelanguage=""><table>
<tr>
<th></th>
</tr>
<tr>
<td>
<pre>0:000&gt; dx Debugger.State.Scripts.TitleFinder.Contents.findTitle()
Debugger.State.Scripts.TitleFinder.Contents.findTitle() : C:\Windows\System32\notepad.exe</pre>
</td>
</tr>
</table></span></div>
<p>Calling  the LINQ version, findTitleWithLINQ() also returns notepad.exe</p>
<div class="code"><span codelanguage=""><table>
<tr>
<th></th>
</tr>
<tr>
<td>
<pre>0:000&gt; dx Debugger.State.Scripts.TitleFinder.Contents.findTitleWithLINQ()
Debugger.State.Scripts.titleFinder.Contents.findTitleWithLINQ() : C:\Windows\System32\notepad.exe</pre>
</td>
</tr>
</table></span></div>
<h2><a id="related_topics"></a>Related topics</h2>
<dl>
<dt><a href="#Bookmark1175">JavaScript Debugger Scripting</a></dt></dl></div></div>	
	<div id="winchm_template_footer">Copyright &copy; 2019. All rights 
reserved. (To change the copyright info, just edit it in template.)</div>
</div>

</body>
</html>
